package com.imooc.user.controller;

import com.imooc.api.BaseController;
import com.imooc.api.controller.user.PassportControllerApi;
import com.imooc.enums.UserStatus;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.pojo.AppUser;
import com.imooc.pojo.bo.LogoutBO;
import com.imooc.pojo.bo.RegistLoginBO;
import com.imooc.user.service.UserService;
import com.imooc.utils.IPUtil;
import com.imooc.utils.JsonUtils;
import com.imooc.utils.SMSUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

/**
 * 用户注册登录
 */
@Slf4j
@RestController
public class PassportController extends BaseController implements PassportControllerApi {

    @Autowired
    private SMSUtils smsUtils;

    @Autowired
    private UserService userService;

    /**
     * 获得短信验证码
     */
    @Override
    public GraceJSONResult getSMSCode(String mobile, HttpServletRequest request) {
        // 注意有拦截器校验是否在60秒内多次请求验证码

        // 获得用户ip
        String userIp = IPUtil.getRequestIp(request);
        // 根据用户的ip进行限制, 限制用户在60秒内只能获得一次验证码, 逻辑是将用户的ip放入redis中
        redis.setnx60s(MOBILE_SMSCODE + ":" + userIp, userIp);
        // 生成随机验证码
        String random = (int) ((Math.random() * 9 + 1) * 100000) + "";

        // 发送短信
        // smsUtils.sendSMS(mobile, random);
        // 短信服务了解一下即可, 这里直接打印到控制台
        log.info("手机号验证码是 = {}", random);

        // 把验证码存入redis, 用于后续进行验证
        redis.set(MOBILE_SMSCODE + ":" + mobile, random, 30 * 60);
        return GraceJSONResult.ok();
    }

    /**
     * 一键注册登录接口
     */
    @Override
    public GraceJSONResult doLogin(@Valid RegistLoginBO registLoginBO, BindingResult result, HttpServletResponse response) {
        // fixme: 这个 valid 校验, 在接口层和实现类都加注解

        // 判断 BindingResult 中是否保存了错误的验证信息, 如果有则需要返回(校验注解产生的错误会被放在这个对象中)
        if (result.hasErrors()) {
            Map<String, String> map = getErrors(result);
            return GraceJSONResult.errorMap(map);
        }

        // 手机号和验证码信息
        String mobile = registLoginBO.getMobile();
        String smsCode = registLoginBO.getSmsCode();

        // 校验验证码是否匹配
        String redisSMSCode = redis.get(MOBILE_SMSCODE + ":" + mobile);
        if (StringUtils.isBlank(redisSMSCode) || !redisSMSCode.equalsIgnoreCase(smsCode)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.SMS_CODE_ERROR);
        }

        // 查询数据库, 判断该用户注册
        AppUser user = this.userService.queryMobileIsExist(mobile);
        if (user != null && Objects.equals(user.getActiveStatus(), UserStatus.FROZEN.type)) {
            // 如果用户不为空, 并且状态为冻结, 则直接抛出异常, 禁止登录
            return GraceJSONResult.errorCustom(ResponseStatusEnum.USER_FROZEN);
        } else if (user == null) {
            // 如果用户没有注册过, 则为null, 需要注册信息入库
            user = userService.createUser(mobile);
        }

        // 将非冻结状态下的账号, 保存 token 和 user 信息到 redis 和 cookie 中
        int userActiveStatus = user.getActiveStatus();
        if (userActiveStatus != UserStatus.FROZEN.type) {
            String uToken = UUID.randomUUID().toString();
            redis.set(REDIS_USER_TOKEN + ":" + user.getId(), uToken);
            redis.set(REDIS_USER_INFO + ":" + user.getId(), JsonUtils.objectToJson(user));
            addCookie(response, "utoken", uToken, COOKIE_MONTH);
            addCookie(response, "uid", user.getId(), COOKIE_MONTH);
        }

        // 用户登录或注册成功以后, 需要删除 redis 中的短信验证码, 验证码只能使用一次, 用过后则作废
        redis.del(MOBILE_SMSCODE + ":" + mobile);

        // 返回用户状态
        return GraceJSONResult.ok(userActiveStatus);
    }

    /**
     * 用户退出登录
     */
    @Override
    public GraceJSONResult logout(LogoutBO logoutBO, HttpServletResponse response) {
        // 清除令牌
        redis.del(REDIS_USER_TOKEN + ":" + logoutBO.getUserId());
        // 清除 cookie 中的 token、userId 信息
        addCookie(response, "utoken", "", COOKIE_DELETE);
        addCookie(response, "uid", "", COOKIE_DELETE);
        return GraceJSONResult.ok();
    }
}
